package br.ufrj.ppgi.bri.control;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.ClassExpressionType;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLException;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.PrefixManager;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.util.DefaultPrefixManager;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;

public class WalkerBC {
	private OWLOntology ontologia;
	private OWLOntologyManager manager;
	private OWLDataFactory df;
	private OWLAnnotationProperty label;
	private OWLAnnotationProperty comment;
    private OWLReasonerFactory reasonerFactory;
    private OWLReasoner reasoner;
	private PrefixManager pm;
	private Set<OWLClassExpression> subclasses, eqclasses;

	public WalkerBC() {
		this("http://www.co-ode.org/ontologies/pizza/pizza.owl");
//		this("http://www.owl-ontologies.com/Ontology1276099586.owl");
	}

	public WalkerBC(String url) {
		try {
			this.manager = OWLManager.createOWLOntologyManager();
			manager.setSilentMissingImportsHandling(true);
//			final String filename = "/WEB-INF/ontologies/CrimesFinanceiros.owl";
			final String filename = "/WEB-INF/ontologies/pizza.owl";
			ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();

			if (servletContext != null) {
				this.ontologia = manager.loadOntologyFromOntologyDocument(servletContext.getResourceAsStream(filename));
				this.pm = new DefaultPrefixManager(url + "#");
			} else {
				IRI iri = IRI.create(url);
				this.ontologia = manager.loadOntologyFromOntologyDocument(iri);
				this.pm = new DefaultPrefixManager(url + "#");
			}

			this.df = manager.getOWLDataFactory();
			String rfName = "org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory";
			this.reasonerFactory = (OWLReasonerFactory) Class.forName(rfName).newInstance();
			this.reasoner = reasonerFactory.createNonBufferingReasoner(ontologia);
			label = df.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_LABEL.getIRI());
			comment = df.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_COMMENT.getIRI());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void descreveClasse(OWLClass classe, Collection<String> lista) throws OWLException {
        for (OWLAnnotation annotation : classe.getAnnotations(ontologia, label)) {
            if (annotation.getValue() instanceof OWLLiteral) {
                OWLLiteral val = (OWLLiteral) annotation.getValue();
                lista.add(val.getLiteral());
            }
        }

        for (OWLClassExpression cle : classe.getEquivalentClasses(ontologia)) {
        	if (cle.getClassExpressionType() == ClassExpressionType.OWL_CLASS) {
        		descreveClasse(cle.asOWLClass(), lista);
        	}
        }

        for (OWLClassExpression cle : reasoner.getSubClasses(classe, true).getFlattened()) {
        	if (cle.getClassExpressionType() == ClassExpressionType.OWL_CLASS) {
        		descreveClasse(cle.asOWLClass(), lista);
        	}
        }
	}

	public Collection<String> listarTermosRelacionados(String termoOriginal) {
		Collection<String> lista = new ArrayList<String>();
        OWLClass classe = df.getOWLClass(":" + termoOriginal, pm);

        try {
        	descreveClasse(classe, lista);
		} catch (Exception e) {
    		e.printStackTrace();
    	}

		return lista;
	}
}
